Add highlighting for invalid/undone questions and show error messages#1209
Conversation
Co-authored-by: Copilot <copilot@github.com>
|
🪓 PR closed, deleted preview. |
Co-authored-by: Copilot <copilot@github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates response/stimulus validation UX so the “Next” button can remain enabled while unmet requirements are surfaced via inline highlighting and error messaging, and it adds provenance/state needed to make those reveals replayable in analysis mode.
Changes:
- Introduces centralized response-issue evaluation + messaging and uses it to highlight unanswered/invalid questions after a submit attempt.
- Adds stimulus validation reasons/messages (video/iframe/react/vega) and a mechanism to reveal stimulus errors on Next click.
- Extends store state and tests to support the new “attempted submit” behavior and new messaging.
Reviewed changes
Copilot reviewed 35 out of 35 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/example-mvnv.spec.ts | Adjusts MVNV Playwright test timing/selection behavior to reduce flakiness. |
| tests/demo-video.spec.ts | Updates expectations: Next is enabled but reveals force-completion message until video ends. |
| tests/demo-vega.spec.ts | Updates expectation: Next starts enabled for vega trial. |
| tests/demo-form-elements.spec.ts | Updates tests for “click Next to reveal validation errors” flow + default/custom response behavior. |
| src/store/types.ts | Extends validation types with reason/message and adds submit-attempt tracking fields. |
| src/store/store.tsx | Initializes stimulus validation via helper; persists reason/message; adds submit-attempt reducers. |
| src/store/hooks/useNextStep.ts | Removes response-validity gating from Next disabled state; persists responseSubmitAttempted in answers. |
| src/store/hooks/useNextStep.spec.tsx | Updates tests for new Next-disable semantics + persisted submit-attempt flag. |
| src/controllers/VideoController.tsx | Adds reason/message for forceCompletion gating; clears gate on missing asset; avoids mutations in analysis. |
| src/controllers/VegaController.tsx | Adds analysis guard; clears gate on spec load/parse failures; passes reason/message through. |
| src/controllers/ReactComponentController.tsx | Adds analysis guard; clears gate on missing component/runtime error; passes reason/message through. |
| src/controllers/IframeController.tsx | Avoids mutating stimulus validation/answers during analysis replay. |
| src/controllers/ErrorBoundary.tsx | Adds optional onError callback hook for controller-level recovery. |
| src/controllers/ComponentController.tsx | Adds stimulus error message rendering + stimulus error highlighting styles + provenance helpers. |
| src/components/response/utils.ts | Refactors response validation helpers to use the new responseErrors utilities and standardized required message. |
| src/components/response/utils.spec.ts | Updates/expands unit tests for required/other/don’t-know validation and response issue summarization. |
| src/components/response/stimulusProvenance.ts | New: stores showStimulusErrors in stimulus provenance graph for replay. |
| src/components/response/stimulusErrors.ts | New: stimulus validation initialization + issue/message generation helpers. |
| src/components/response/stimulusErrors.spec.ts | New unit tests for stimulus validation/message helpers. |
| src/components/response/responseErrors.ts | New: centralized response issue evaluation, messages, and summarization logic. |
| src/components/response/*Input.tsx | Plumbs computed error strings into individual inputs and standardizes error styling. |
| src/components/response/ResponseSwitcher.tsx | Computes per-response error message + wrapper highlighting based on submit-attempt reveal state. |
| src/components/response/ResponseBlock.tsx | Implements submit-attempt tracking, sticky summary, “Next question” scroll, and Next-click reveal logic. |
| src/components/NextButton.tsx | Adds onNext callback to delegate Next-click behavior to ResponseBlock. |
| public/demo-form-elements/config.json | JSON formatting fix for defaults (no functional change). |
Comments suppressed due to low confidence (1)
src/components/response/ResponseBlock.tsx:392
- This effect invokes
updateResponseBlockValidation(...)directly (withoutstoreDispatch). As written it doesn’t update Redux state, so any intent to sync validation/provenance when loading a stored answer won’t happen here (only later effects may incidentally update it). Dispatch the action (or remove this call if it’s redundant).
useEffect(() => {
if (storedAnswer) {
answerValidator.setInitialValues(generateInitFields(responses, storedAnswer));
answerValidator.reset();
updateResponseBlockValidation({
location,
identifier,
status: answerValidator.isValid(),
values: structuredClone(answerValidator.values),
provenanceGraph: trrack.graph.backend,
});
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
# Conflicts: # src/store/hooks/useNextStep.ts
# Conflicts: # src/components/response/MatrixInput.tsx
JackWilb
left a comment
There was a problem hiding this comment.
Approved after verifying the branch against origin/dev and confirming the follow-up fixes for persisted stimulus validation state and iframe answer/provenance ordering.
Does this PR close any open issues?
Closes #937
Closes #1205
Give a longer description of what this PR addresses and why it's needed
Provide pictures/videos of the behavior before and after these changes (optional)
demo-form-elementsTest
Screen.Recording.2026-04-21.at.11.10.23.PM.mov
Are there any additional TODOs before this PR is ready to go?
TODOs: